package com.vf.cloud.paas.app.agent.mvc.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.StrKit;
import com.vf.cloud.paas.app.agent.common.domain.Project;
import com.vf.cloud.paas.app.agent.common.server.signalling.pool.StreamerPool;
import com.vf.cloud.paas.app.agent.common.util.KeyUtil;
import com.vf.cloud.paas.app.agent.mvc.service.IRender;
import com.vf.cloud.paas.common.cirrus.Cirrus;
import com.vf.cloud.paas.common.service.IRedis;
import com.vf.cloud.paas.common.util.PrefixUtil;
import com.vf.cloud.paas.common.util.R;
import com.vf.cloud.paas.common.vo.ROrder;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class RenderImpl implements IRender {

	class ConsoleThread implements Runnable {
		private int key;
		private String exeName = null;
		private BufferedReader bfr = null;

		public ConsoleThread(int key, String exeName, BufferedReader bfr) {
			this.bfr = bfr;
			this.exeName = exeName;
			this.key = key;
		}

		@Override
		public void run() {
			
			//发送使用 gpu
			try {
				while ((bfr.readLine()) != null) {
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (bfr != null) {
					try {
						bfr.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			log.error("Client:" + key + ">> App:" + exeName + " >> closed.");
			//恢复gpu
		}
	}

	private int startExe(int key, String exeName, String cmd) {
		Process process;
		try {
			Runtime runtime = Runtime.getRuntime();
			process = runtime.exec(cmd);
			new Thread(new ConsoleThread(key, exeName,
					new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")))).start();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return -1;
	}

	@Autowired
	private IRedis redisImpl;
	
	@Value("${agent.project.path}")
	private String projectPath;

	@Value("${master.ip}")
	private String agentIp;

	@Value("${agent.signalling.streamerPort}")
	private String streamerPort;

	@Value("${agent.signalling.playerPort}")
	private String playerPort;

	@Value("${agent.signalling.streamerIP}")
	private String streamerIP;

	@Value("${agent.signalling.playerIP}")
	private String playerIP;

	@Value("${agent.token}")
	private String agentToken;

	@Override
	public R<ROrder> AnyOrder(JSONObject order) {

		if (order == null) {
			return R.failed("参数必填.");
		}
		
		String GPUIndex=order.getString("GPUIndex");
		if(!order.containsKey("appid") || !order.containsKey("projectid") || !order.containsKey("resX") || !order.containsKey("resY")|| !order.containsKey("index")) {
			Cirrus.renderClient.sendGpuInfo(GPUIndex,GPUIndex.replaceFirst(PrefixUtil.GPU_Free, PrefixUtil.GPU_Used));
			return R.failed("参数必填.");
		}

		String appid=order.getString("appid");
		String projectid=order.getString("projectid");
		int resX=order.getInteger("resX");
		int resY=order.getInteger("resY");
		int index=order.getInteger("index");
		
		
		if (StrKit.isBlank(appid)||StrKit.isBlank(projectid)) {
			Cirrus.renderClient.sendGpuInfo(GPUIndex,GPUIndex.replaceFirst(PrefixUtil.GPU_Free, PrefixUtil.GPU_Used));
			return R.failed("参数必填.");
		}

		Project project = Project.dao.findById(projectid);

		if (project == null) {
			Cirrus.renderClient.sendGpuInfo(GPUIndex,GPUIndex.replaceFirst(PrefixUtil.GPU_Free, PrefixUtil.GPU_Used));
			return R.failed("应用不存在或未同步至渲染节点.");
		}
		
		if(resX == 0 || resY == 0) {
			resX=project.getResX();
			resY=project.getResY();
		}

		int key = KeyUtil.genKey();
		String projectAbsolutePath = projectPath + project.getExeRelativePath();
		String PixelStreamingIP = "ws://" + streamerIP + ":" + streamerPort + "/" + key;
		String format = "%s -RenderOFFscreen -AudioMixer -AllowPixelStreamingCommands -PixelStreamingHideCursor=true -ForceRes ResX=%s ResY=%s -GraphicsAdapter=%s -AppId=%s -PixelStreamingURL=%s";
		String cmd = String.format(format, projectAbsolutePath, resX, resY, index, appid, PixelStreamingIP);
		startExe(key, project.getName(), cmd);
		
		redisImpl.add(key, GPUIndex);
		
		log.info(">>Streamer Check  running");
		if (isBooted(key)) {
			String PlayerUL = "ws://" + playerIP + ":" + playerPort + "/" + key;
			ROrder rorder = new ROrder();
			rorder.setAppId(appid);
			rorder.setEIO(key + "");
			rorder.setUrl(PlayerUL);
			Cirrus.renderClient.sendGpuInfo(GPUIndex.replaceFirst(PrefixUtil.GPU_Free, PrefixUtil.GPU_Used),GPUIndex);
			return R.ok(rorder);
		} else {
			Cirrus.renderClient.sendGpuInfo(GPUIndex,GPUIndex.replaceFirst(PrefixUtil.GPU_Free, PrefixUtil.GPU_Used));
			return R.failed("启动场景渲染超时.");
		}

	}

	private boolean isBooted(int key) {
		boolean isSucc = false;
		int idleTimeout = 60;
		int time = 0;
		while (true) {
			if (StreamerPool.containsToken(key + "")) {
				isSucc = true;
				break;
			}

			if (time > idleTimeout) {
				isSucc = false;
				break;
			}

			try {
				Thread.sleep(1000);
				time++;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return isSucc;

	}

}
